// 版权归 Epic Games, Inc. 所有。保留所有权利。

#include "LyraHotfixManager.h"
#include "UObject/UObjectIterator.h"
#include "Engine/NetDriver.h"
#include "DeviceProfiles/DeviceProfileManager.h"
#include "DeviceProfiles/DeviceProfile.h"
#include "Settings/LyraSettingsLocal.h"
#include "HAL/MemoryMisc.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraHotfixManager)

// 初始化静态成员变量
int32 ULyraHotfixManager::GameHotfixCounter = 0;

/** 构造函数 */
ULyraHotfixManager::ULyraHotfixManager()
{
#if !UE_BUILD_SHIPPING
	// 在非发布版本中注册屏幕消息回调
	OnScreenMessageHandle = FCoreDelegates::OnGetOnScreenMessages.AddUObject(this, &ULyraHotfixManager::GetOnScreenMessages);
#endif // !UE_BUILD_SHIPPING

	// 注册热修复完成回调
	HotfixCompleteDelegateHandle = AddOnHotfixCompleteDelegate_Handle(FOnHotfixCompleteDelegate::CreateUObject(this, &ThisClass::OnHotfixCompleted));
}

/** 初始化函数 */
void ULyraHotfixManager::Init()
{
	Super::Init(); // 调用父类初始化
}

/** 热修复完成回调函数 */
void ULyraHotfixManager::OnHotfixCompleted(EHotfixResult HotfixResult)
{
	// 重新加载所有活跃网络驱动的DDoS检测配置（镜像RepGraph代码）
	for (TObjectIterator<UNetDriver> It; It; ++It)
	{
		if (It->IsServer()) // 如果是服务器
		{
			UE_LOG(LogHotfixManager, Log, TEXT("重新加载网络驱动的DDoS检测设置: %s"), *It->GetName());

			It->DDoS.InitConfig(); // 初始化DDoS配置
		}
	}

	// 如果有待处理的设备配置热修复
	if (bHasPendingDeviceProfileHotfix)
	{
		UE_LOG(LogHotfixManager, Log, TEXT("重新应用热修复后的设备配置"));

		bHasPendingDeviceProfileHotfix = false; // 重置标志
		UDeviceProfileManager::Get().ReapplyDeviceProfile(); // 重新应用设备配置

		ULyraSettingsLocal* GameSettings = ULyraSettingsLocal::Get(); // 获取游戏设置
		GameSettings->OnHotfixDeviceProfileApplied(); // 调用设备配置应用完成回调
	}

#if ENABLE_SHARED_MEMORY_TRACKER
	// 打印内存差异
	FSharedMemoryTracker::PrintMemoryDiff(TEXT("热修复完成"));
#endif
}

/** 析构函数 */
ULyraHotfixManager::~ULyraHotfixManager()
{
	// 清除热修复完成委托
	ClearOnHotfixCompleteDelegate_Handle(HotfixCompleteDelegateHandle);

#if !UE_BUILD_SHIPPING
	// 移除屏幕消息回调
	FCoreDelegates::OnGetOnScreenMessages.Remove(OnScreenMessageHandle);
#endif // !UE_BUILD_SHIPPING
}

/** 判断是否需要对文件进行热修复处理 */
bool ULyraHotfixManager::WantsHotfixProcessing(const FCloudFileHeader& FileHeader)
{
	bool bWantsProcessing = Super::WantsHotfixProcessing(FileHeader); // 先调用父类判断
	if (!bWantsProcessing) // 如果父类不需要处理
	{
		// 定义支持的文件列表
		FString SupportedFiles[] = {
			TEXT("AssetMigrations.ini")
		};

		// 检查文件是否在支持列表中
		for (FString SupportedFile : SupportedFiles)
		{
#if !UE_BUILD_SHIPPING
			// 在非发布版本中添加调试前缀
			if (!DebugPrefix.IsEmpty())
			{
				SupportedFile = DebugPrefix + SupportedFile;
			}
#endif
			if (SupportedFile == FileHeader.FileName) // 文件名匹配
			{
				bWantsProcessing = true; // 需要处理
				break;
			}
		}
	}
	return bWantsProcessing; // 返回处理标志
}

/** 热修复INI文件 */
bool ULyraHotfixManager::HotfixIniFile(const FString& FileName, const FString& IniData)
{
	// 检查是否是设备配置文件且没有待处理的设备配置热修复
	if (!bHasPendingDeviceProfileHotfix && FileName.EndsWith(TEXT("DEVICEPROFILES.INI"), ESearchCase::IgnoreCase))
	{
		FConfigFile DeviceProfileHotfixConfig; // 设备配置热修复配置
		DeviceProfileHotfixConfig.CombineFromBuffer(IniData, FileName); // 从缓冲区合并配置
		TSet<FString> Keys; // 键集合
		for (const auto& DPSection : AsConst(DeviceProfileHotfixConfig)) // 遍历所有配置节
		{
			FString DeviceProfileName, DeviceProfileClass;
			// 分割设备配置名称和类
			if (DPSection.Key.Split(TEXT(" "), &DeviceProfileName, &DeviceProfileClass) && DeviceProfileClass == *UDeviceProfile::StaticClass()->GetName())
			{
				Keys.Add(DeviceProfileName); // 添加到键集合
			}
		}

		// 检查是否有热修复的设备配置被当前活跃配置引用
		bHasPendingDeviceProfileHotfix = UDeviceProfileManager::Get().DoActiveProfilesReference(Keys);
		UE_LOG(LogHotfixManager, Log, TEXT("活跃设备配置被热fix引用 = %d"), (uint32)bHasPendingDeviceProfileHotfix);
	}

	return Super::HotfixIniFile(FileName, IniData); // 调用父类处理
}

/** 应用热修复处理 */
bool ULyraHotfixManager::ApplyHotfixProcessing(const FCloudFileHeader& FileHeader)
{
	// 允许自动下载JSON文件
	const FString Extension = FPaths::GetExtension(FileHeader.FileName); // 获取文件扩展名
	if (Extension == TEXT("json")) // 如果是JSON文件
	{
		return true; // 直接返回成功
	}
	
	const bool bResult = Super::ApplyHotfixProcessing(FileHeader); // 调用父类处理
	if (bResult && FileHeader.FileName.EndsWith(TEXT("GAME.INI"), ESearchCase::IgnoreCase)) // 处理成功且是游戏INI文件
	{
		GameHotfixCounter++; // 增加游戏热修复计数器

		// 如果有待处理的游戏热修复
		if (bHasPendingGameHotfix)
		{
			bHasPendingGameHotfix = false; // 重置标志
			OnPendingGameHotfixChanged.Broadcast(bHasPendingGameHotfix); // 广播状态变化
		}
	}

	return bResult; // 返回处理结果
}

/** 判断在从INI文件修补时是否应警告缺失的资源 */
bool ULyraHotfixManager::ShouldWarnAboutMissingWhenPatchingFromIni(const FString& AssetPath) const
{
	// 只对Engine和Game路径下的资源发出警告
	return AssetPath.StartsWith(TEXT("/Engine/")) || AssetPath.StartsWith(TEXT("/Game/"));
}

/** 从INI文件修补资源 */
void ULyraHotfixManager::PatchAssetsFromIniFiles()
{
#if ENABLE_SHARED_MEMORY_TRACKER
	// 打印内存差异
	FSharedMemoryTracker::PrintMemoryDiff(TEXT("开始 - 从INI文件修补资源"));
#endif

	Super::PatchAssetsFromIniFiles(); // 调用父类方法

#if ENABLE_SHARED_MEMORY_TRACKER
	// 打印内存差异
	FSharedMemoryTracker::PrintMemoryDiff(TEXT("结束 - 从INI文件修补资源"));
#endif
}

/** 检查热修复可用性时的回调 */
void ULyraHotfixManager::OnHotfixAvailablityCheck(const TArray<FCloudFileHeader>& PendingChangedFiles, const TArray<FCloudFileHeader>& PendingRemoveFiles)
{
	bool bNewPendingGameHotfix = false; // 新的待处理游戏热修复标志
	// 遍历待更改文件
	for (int32 Idx = 0; Idx < PendingChangedFiles.Num(); Idx++)
	{
		// 检查是否是游戏INI文件
		if (PendingChangedFiles[Idx].FileName.EndsWith(TEXT("GAME.INI"), ESearchCase::IgnoreCase))
		{
			bNewPendingGameHotfix = true; // 设置标志
			break;
		}
	}

	// 如果有新的游戏热修复且之前没有待处理的
	if (bNewPendingGameHotfix && !bHasPendingGameHotfix)
	{
		bHasPendingGameHotfix = true; // 设置标志
		OnPendingGameHotfixChanged.Broadcast(bHasPendingGameHotfix); // 广播状态变化
	}
}

#if !UE_BUILD_SHIPPING
/** 获取屏幕消息 */
void ULyraHotfixManager::GetOnScreenMessages(TMultiMap<FCoreDelegates::EOnScreenMessageSeverity, FText>& OutMessages)
{
	// TODO 任何消息/错误
}
#endif // !UE_BUILD_SHIPPING

/** 请求从INI文件修补资源 */
void ULyraHotfixManager::RequestPatchAssetsFromIniFiles()
{
	// 如果还没有请求处理
	if (!RequestPatchAssetsHandle.IsValid())
	{
		// 添加定时器委托
		RequestPatchAssetsHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateWeakLambda(this, [this](float DeltaTime) {
			RequestPatchAssetsHandle.Reset(); // 重置句柄
			UE_LOG(LogHotfixManager, Display, TEXT("由于新插件，热修复管理器重新调用PatchAssetsFromIniFiles"));
			PatchAssetsFromIniFiles(); // 调用修补函数
			return false; // 只执行一次
		}));
	}
}

/** 开始热修复过程 */
void ULyraHotfixManager::StartHotfixProcess()
{
	// 在编辑器中跳过热修复
	if (GIsEditor)
	{
		UE_LOG(LogHotfixManager, Display, TEXT("在开发模式下跳过热修复。"));
		TriggerHotfixComplete(EHotfixResult::SuccessNoChange); // 触发热修复完成
		return;
	}

#if ENABLE_SHARED_MEMORY_TRACKER
	// 打印内存差异
	FSharedMemoryTracker::PrintMemoryDiff(TEXT("开始热修复过程"));
#endif

	Super::StartHotfixProcess(); // 调用父类开始热修复
}